
# encoding=utf-8
# 2020/7/21
from BasicOperation import *
import threading  # 需要开一个线程监视处理是否完成
import time  # 需要用到延迟sleep()函数
from Tabulate import tabulate


class DNAC:
    def __init__(self,host,username,
                 password,version):
        self.Operator = BasicOperation(host,username,
                 password,version='v1')

    # -----获取控制器所管辖的所有网元的粗略信息并罗列打印-----
    def get_device_list(self):

        device_dict = self.Operator.get('network-device')
        # 接下来筛选感兴趣的信息，便于tabulate打印
        return device_dict['response']

    # -----遍历取出每一个网元的ID，准备获取其接口信息(可改)-----
    def get_all_device_id(self, device_dict):
        for device in device_dict['response']:
            print("Fetching Interfaces for Device Id ----> {}".format(device['id']))
            print('\n')
            self.get_device_int(device['id'])
            print('\n')

    # -----获取网元的接口信息并罗列打印-----
    def get_device_int(self, device_id):
        interfaces_info_dict = self.Operator.get('interface/network-device/{}'.format(device_id))
        # 接下来筛选感兴趣的信息，便于tabulate打印

        if isinstance(interfaces_info_dict['response'], dict):
            interfaces_info_dict['response'] = []
            return interfaces_info_dict['response']

        return interfaces_info_dict['response']

    # -----获取所管辖的host主机信息-----
    def get_host(self):
        try:
            response_dict = self.Operator.get("host")

            return response_dict['response']
        except:
            print("Something went wrong with the GET /host request!")
            return []

    def get_host_and_device(self):
        '''获取所管辖的所有网元、主机的信息'''
        ip_list = []
        idx = 0
        # 先获取host的信息
        try:
            response_json = self.Operator.get(api="host")
            i = 0
            if response_json["response"] != []:
                for item in response_json["response"]:
                    i += 1
                    ip_list.append([i, "host", item["hostIp"]])
                idx = i  # This idx(sequential number) is used to tag host and network device
        except:
            print("Something went wrong. Cannot get the host IP list")
            # 再获取device的信息
        try:
            response_json = self.Operator.get(api="network-device")
            print("Status: of GET /network-device ")
            if response_json["response"] != []:
                for item in response_json["response"]:
                    idx += 1
                    ip_list.append([idx, "network device", item["managementIpAddress"]])
        except:
            print("Something went wrong! Cannot get the network device IP list!")

        # 通过tabulate打印出来信息
        if len(ip_list) < 2:
            print("You need at least two hosts or network devices to perform a path trace!")
            sys.exit()
        print(tabulate(ip_list, headers=['number', 'type', 'ip'], tablefmt="rst"))
        return ip_list

    def select_ip(self,user_input, ip_list, idx=2):
        '''让用户做出选择，然后该函数返回对应的IP'''
        ip = ""
        while True:

            if user_input.isdigit():
                if int(user_input) in range(1, len(ip_list) + 1):
                    ip = ip_list[int(user_input) - 1][idx]  # The idx is the position of IP
                    return ip
                else:
                    print("Oops! The number you selected is out of range. Please try again or enter 'exit'")
            else:
                print("Oops! The input you entered is not a number. Please try again or enter 'exit'")

    def create_analysis(self,s_ip, d_ip):
        '''创建analysis应用。这不是一下子就创建好的，需要一段时间，但是会先返回应用ID号。'''
        # 下面两行代码才是重点，创建flow-analysis
        path_data = {"sourceIP": s_ip, "destIP": d_ip}
        response_json = self.Operator.post(api="flow-analysis", data=path_data, )

        try:
            flowAnalysisId = response_json["response"]["flowAnalysisId"]  # 取得flowAnalysisId
            return flowAnalysisId
        except:
            print("\n For some reason, you cannot get the flowAnalysisId")
            sys.exit()

    def check_status(self,status, flowAnalysisId, cotroller):  # 监视进度
        '''通过应用ID号来检查analysis程序的构建进度（也会打印），若构建完毕，则打印最终结果'''
        count = 0
        #  以下是表明出问题了的话
        while status != "COMPLETED":
            if status == "FAILED":
                print(
                    "Unable to find the full path. No traceroute or netflow information was found. The path calculation failed.")
                print("\n------ End of path trace ! ------")
                return
            print("\nTask is not finished yet, sleep 1 second then try again")
            time.sleep(1)
            count += 1
            if count > 30:  # timeout after ~ 30 seconds
                print(
                    "\nScript timed out. No routing path was found. Please try using a different source and destination !")
                print("\n------ End of path trace ! ------")
                return
            try:  # 这里才使用ID API***
                response_json = cotroller.get(api="flow-analysis/" + flowAnalysisId)
                print("Response from GET /flow-analysis/" + flowAnalysisId)
                # print(json.dumps(response_json, indent=4))
                self.pathTrackResponse = response_json["response"]
                status = response_json["response"]["request"]["status"]
                print("\n Check status here: ", status, " \n")
            except:  # APi访问不了的话
                # Something is wrong
                print("\nSomething went wrong while running get /flow-analysis/{flowAnalysisId}")
        print("\n------ End of path trace ! ------")

    def path_track(self,start_num,end_num, nd_list):
        '''实现两个IP间的ARP转发路径分析'''
        print(" Note: Not all source/destination ip address pairs will return a path. No route!  \n")
        s_ip = self.select_ip(start_num,nd_list)  # ip_idx (=2) is the position of IP in the list
        d_ip = self.select_ip(end_num,nd_list)  # ip_idx (=2) is the position of IP in the list
        flowAnalysisId = self.create_analysis(s_ip, d_ip)

        self.check_status('', flowAnalysisId, self.Operator)
        return self.pathTrackResponse


if __name__=="__main__":
    myDNAC = DNAC("sandboxdnac.cisco.com:443","devnetuser","Cisco123!")
    myDNAC.get_device_list()
    myDNAC.get_host()

